import backtrader as bt
from datetime import datetime
from strategy.utils.BaoStockPandasData import BaoStockPandasData
from utils.DataSource import get_stock_data2

class ValueInvestingStrategy(bt.Strategy):
    params = (
        ('pe_threshold', 10),  # 市盈率阈值，低于此值视为低估
        ('order_percentage', 0.95),  # 交易资金占总资金的百分比
    )

    def __init__(self):
        self.data_close = self.datas[0].close
        self.order = None

    def next(self):
        # 这里简化处理，假设市盈率数据已经集成到Backtrader数据中（实际上需要通过其他方式集成）
        pe_ratio = self.getsizer().getpe()  # 假设有个方法可以从数据中获取市盈率
        
        if self.order:
            return  # 如果有订单在执行，则不执行新的买卖操作

        if not self.position and pe_ratio < self.params.pe_threshold:  # 市盈率低于阈值且无持仓，买入
            amount_to_invest = (self.params.order_percentage * self.broker.cash) / self.data_close
            self.buy(size=amount_to_invest)

    def notify_order(self, order):
        if order.status in [order.Submitted, order.Accepted]:
            return  # 订单状态未最终确定，等待

        if order.status in [order.Completed]:
            if order.isbuy():
                self.log(f"BUY EXECUTED --- Price: {order.executed.price}, Cost: {order.executed.value}, Commission: {order.executed.comm}")
            else:  # Sell
                self.log(f"SELL EXECUTED --- Price: {order.executed.price}, Size: {order.executed.size}, Commission: {order.executed.comm}")

        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            self.log('Order Canceled/Margin/Rejected')

        self.order = None

# 回测设置示例
if __name__ == '__main__':
    cerebro = bt.Cerebro()

    # 假设已经通过某种方式（如AkShare）获取并处理了数据，并且将市盈率数据整合到了数据馈送中
    #data = bt.feeds.YahooFinanceData(dataname="000001.SZ", fromdate=datetime(2020, 1, 1), todate=datetime(2021, 12, 31))
    df = get_stock_data2("sh.603057", "2020-01-01", "2024-09-27")
    data = BaoStockPandasData(dataname=df)
    cerebro.adddata(data)

    # 自定义Sizer，以便在策略中获取市盈率等财务数据
    class ValueSizer(bt.Sizer):
        def __init__(self, getsizer, **kwargs):
            super(ValueSizer, self).__init__(**kwargs)
            self.getsizer = getsizer

    cerebro.addsizer(ValueSizer,getsizer=23)

    cerebro.addstrategy(ValueInvestingStrategy, pe_threshold=10)

    cerebro.broker.setcash(100000.0)
    cerebro.broker.set_coc(True)  # 现金交易模式

    print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
    cerebro.run()
    print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
    
    #量化价值投资策略通常涉及到对股票的基本面数据进行分析，以识别出被市场低估的股票。在Backtrader中实现这样的策略，首先需要从外部数据源（如AkShare）获取财务数据，然后根据这些数据制定交易规则。下面是一个简化的示例，展示了如何结合财务指标（如市盈率PE）来筛选股票，并在Backtrader中实现相应的交易逻辑。
    #接下来，我们将基于获取到的财务数据（假设已按需处理），在Backtrader中实现一个简单的价值投资策略，这里以市盈率作为筛选标准，市盈率低于某个阈值时认为股票被低估。
    #请注意，上述代码中的getsizer().getpe()是一个假设的方法，用于从数据中获取市盈率信息。在实际应用中，你可能需要设计一个自定义的数据处理器或Sizer来集成财务数据，并在策略中使用这些数据。AkShare提供的财务数据需要经过适当的预处理和整合，才能在Backtrader策略中使用。